#include "FireEmitter.h"
#include "Renderer.h"
#include "DXMgr.h"
#include "Util.h"
#include "ShaderMgr.h"
#include "Shader.h"
#include "RenderParams.h"

FireEmitter::FireEmitter()
{
}
FireEmitter::~FireEmitter()
{
}
bool FireEmitter::Setup(D3DXVECTOR3 a_pos)
{
	//Used for the size of the point sprite
	m_scale = 0.5f;

	//Setup emitter data
	m_emitRate = 2;
	m_gravity = 5;
	m_maxNumParticles = 100;
	m_pos = a_pos;
	m_velRange = D3DXVECTOR3(3,5,3);
	m_life = 0.9f;
	
	//Currently un-used
	m_colourStart = D3DCOLOR_ARGB(128,255,255,255);
	m_colourEnd = D3DCOLOR_ARGB(128,255,255,255);
	m_scaleStart = 0.5f;
	m_scaleEnd = 5.0f;
	m_rotation = 1.0f;
	//--

	if(FAILED(D3DXCreateTextureFromFile( DXMgr::GetInstance().GetDevice(), "media/flame.png", &m_pTex)))
	{
		return false;
	}

	m_pParticles = new Particle[m_maxNumParticles];

	//Give them all starting data
	for(int i=0; i<m_maxNumParticles; ++i)
	{
		Respawn(m_pParticles[i]);
	}

	D3DXMatrixIdentity(&m_worldMatrix);

	//Create vertex buffer
	HRESULT result  = DXMgr::GetInstance().GetDevice()->CreateVertexBuffer(sizeof(VertexData) * m_maxNumParticles, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, VERTEX_FORMAT_FVF, D3DPOOL_DEFAULT, &m_pVertexBuffer, NULL);
	if(result != D3D_OK)
	{
		return false;
	}
	return true;
}
void FireEmitter::Update(float a_dt)
{
	//----------
	//Particle transforms - get the particles out of screen space
	D3DXMATRIX trans;
	D3DXMATRIX view;
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(&proj, 3.14f / 4, 800.0f/600.0f, 1, 200);
	Renderer::GetInstance().GetActiveCamera()->GetViewMatrix(view);
	//Set the emitter base position
//D3DXMatrixTranslation(&trans, m_pos.x, World::GetInstance().GetTerrainHeight(m_pos.x, m_pos.z), m_pos.z);
	D3DXMatrixMultiply(&trans,&trans,&view);
	D3DXMatrixMultiply(&m_worldMatrix,&trans,&proj);
	//----------

	//Use for rate of emition
	int particlesEmitted = 0;
	for(int i=0; i<m_maxNumParticles; ++i)
	{
		m_pParticles[i].lifeRemaining -= a_dt;

		//If this particle is dead, and can emit another this frame, respawn one
		if(m_pParticles[i].lifeRemaining <= 0.0f)
		{
			//Respawn the particle back to a blank slate
			Respawn(m_pParticles[i]);
		}

		if(m_pParticles[i].lifeRemaining <= 0.0f && particlesEmitted < m_emitRate)
		{
			//If able to re-emit, then emit
			Emit(m_pParticles[i]);
			++particlesEmitted;
		}

		//Update particles
		m_pParticles[i].vel.y += m_gravity * a_dt;
		m_pParticles[i].pos += m_pParticles[i].vel * a_dt;

		//Reduce the alpha by 255/lifeRemaining
		//m_pParticles[i].col = D3DCOLOR_ARGB(10, 255,255,255);
	}
}

void FireEmitter::Respawn(Particle& a_particle)
{
	a_particle.col = m_colourStart;
	a_particle.pos = D3DXVECTOR3(0,0,0);
	a_particle.lifeRemaining = 0.0f;
	a_particle.vel = D3DXVECTOR3(0,0,0);
}
void FireEmitter::Emit(Particle& a_particle)
{
	a_particle.lifeRemaining = m_life;
	a_particle.vel = D3DXVECTOR3(Util::GetRandomFloat(-m_velRange.x, m_velRange.x), Util::GetRandomFloat(m_velRange.y, m_velRange.y), Util::GetRandomFloat(-m_velRange.z, m_velRange.z));
}
void FireEmitter::Render(float a_dt, IDirect3DDevice9 *a_pDevice, const RenderParams& a_renderParams)
{
	//---
	//Set up some render states
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_LIGHTING, false);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_ZWRITEENABLE, false);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSCALEENABLE, true);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSIZE, Util::FtoDw(m_scale));
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSIZE_MIN, Util::FtoDw(5.0f));

	//size of the particles change according to distance
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSCALE_A, Util::FtoDw(0.0f));
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSCALE_B, Util::FtoDw(1.0f));
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSCALE_C, Util::FtoDw(0.0f));

	DXMgr::GetInstance().GetDevice()->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	DXMgr::GetInstance().GetDevice()->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
	//---


	//Copy over data
	m_pVertexBuffer->Lock(0, sizeof(VertexData) * m_maxNumParticles, (void**)&m_pVertData, D3DLOCK_DISCARD);

	for(int i=0; i<m_maxNumParticles; ++i)
	{
		//Only draw if not a dead particle
		if(m_pParticles[i].lifeRemaining > 0.0f)
		{
			m_pVertData->pos = m_pParticles[i].pos;
			m_pVertData->col = m_pParticles[i].col;
			m_pVertData++;
		}
	}

	m_pVertexBuffer->Unlock();

	DXMgr::GetInstance().GetDevice()->SetTexture(0, m_pTex);
	DXMgr::GetInstance().GetDevice()->SetFVF(VERTEX_FORMAT_FVF);
	DXMgr::GetInstance().GetDevice()->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(VertexData));

	DXMgr::GetInstance().GetDevice()->SetTransform(D3DTS_WORLD, &m_worldMatrix);
	

	/*const char* SHADER_NAME = "ParticleShader";
	Shader* pShader = ShaderMgr::GetInstance().Find(SHADER_NAME);
	if(pShader)
	{
		ID3DXEffect* pEffect = pShader->GetEffect();
		if(pEffect)
		{
			pEffect->SetTechnique("RenderTex1");

			//Set texture global variable
			pEffect->SetTexture("g_texture", m_pTex);
			
			//Set matrix global variables
			//Calculate a combined world*view*proj matrix for the vertex shader
			D3DXMATRIX worldViewProj = m_worldMatrix*a_renderParams.GetViewMatrix()*a_renderParams.GetProjMatrix();
			pEffect->SetMatrix("g_worldViewProj", &worldViewProj);
			pEffect->SetMatrix("g_worldMat", &m_worldMatrix);

			//Render with shader
			UINT passCount = 0;
			if(pEffect->Begin(&passCount, 0) == D3D_OK)
			{
				for(UINT passIndex = 0; passIndex < passCount; ++passIndex)
				{		
					if(pEffect->BeginPass(passIndex) == D3D_OK)
					{*/
						//Draw the Particles
						DXMgr::GetInstance().GetDevice()->DrawPrimitive(D3DPT_POINTLIST, 0, m_maxNumParticles);
						/*pEffect->EndPass();
					}
				}
				pEffect->End();
			}
		}
	}*/


	//Reset render states
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_LIGHTING, true);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_POINTSCALEENABLE, false);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
	DXMgr::GetInstance().GetDevice()->SetRenderState(D3DRS_ZWRITEENABLE, true);


}